package edu.pku.sei.mte.serialization;

import java.io.File;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import edu.pku.sei.mte.exceptions.ExceptionRegistry;
import edu.pku.sei.mte.mtemodel.model.MModelGraph;
import edu.pku.sei.mte.mtemodel.mtmodel.ModelType;
import edu.pku.sei.mte.mtemodel.mtmodel.rulebased.RBTransformation;
import edu.pku.sei.mte.runtime.rulebased.RBTEnvironment;
import edu.pku.sei.mte.transformation.ModelTransformationVisitor;
import edu.pku.sei.mte.transformation.VisitorFactory;
import edu.pku.sei.mte.utilities.Utility;

/**
 * @author zhubin
 *
 */
public class PKUTESLoader {
	
	public static final int QVT = 0;
	public static final int GT = 1;
	
	private RBTransformation trans = null;
	
	private RBTEnvironment env = null;
	
	private String targetFileName = null;
	
	public PKUTESLoader(){
		env = new RBTEnvironment();
	}
	
	public void loadModelType(String typeName, String typeFileName){
		EcoreLoader loader = EcoreLoader.getEcoreLoader(typeName, typeFileName);
		loader.load();
	}
	
	public void loadModel(String typeName, String modelFileName, boolean isTarget){
		if(trans == null){
			System.out.println("please load transformation first");
			return;
		}
		ModelType modelType = trans.getModelType(typeName);
		if(modelType == null){
			System.out.println("no " + typeName + " in transformation");
			return;
		}
		MModelGraph model = null;
		if(modelFileName != null && !modelFileName.equals("")){
			EcoreXMILoader loader = new EcoreXMILoader();
			model = loader.load(EcoreLoader.getEcoreLoader(modelType.getTypeGraph()), modelFileName);
		}
		if(model == null){
			model = new MModelGraph();
			model.setTypeGraph(modelType.getTypeGraph());
		} else if(!model.getTypeGraph().equals(modelType.getTypeGraph())){
			System.out.println("typeGraphs are not match ");
			return;
		}
		env.getModelCollection().put(modelType, model);
		if(isTarget){
			env.setTarget(modelType);
		}
	}
	
	public void loadTransformation(String filename){
		File file = new File(filename);
		if(!file.exists()){
			System.out.println("file not exist!");
			return;
		}
		EcoreTransformationLoader transLoader = new EcoreTransformationLoader();
		try {
			trans = transLoader.load(file);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		env.setTransformation(trans);
	}

	public void loadExceptionRegistry(String filename){
		ExceptionRegistryLoader loader = new ExceptionRegistryLoader();
		ExceptionRegistry reg = loader.load(filename, trans);
		env.getExhandler().registerExceptions(reg);
	}
	
	public void saveTargetModel(String filename){
		if(filename != null && !filename.equals(""))
			targetFileName = filename;
		if(targetFileName != null && !targetFileName.equals("")){
			EcoreXMISaver saver = new EcoreXMISaver();
			saver.save(env.getModelGraph(env.getTarget()), targetFileName);
		}
	}
	
	public RBTransformation getTrans() {
		return trans;
	}

	public RBTEnvironment getEnv() {
		return env;
	}
	
	public void load(String filename){
		load(Utility.loadXML(filename));
	}

	public void load(Element root) {
		String semantic = root.getAttribute("control").toLowerCase();
		String mode = root.getAttribute("mtmode").toLowerCase();
		ModelTransformationVisitor mtv = VisitorFactory.INSTANCE.getModelTransformationVisitor(semantic, mode, env);
		env.setMtVisitor(mtv);
		NodeList types = root.getElementsByTagName("type");
		int length = types.getLength();
		for(int i=0;i<length;i++){
			Node n = types.item(i);
			if(n.getNodeType()!=Node.ELEMENT_NODE)
				continue;
			Element type = (Element) n;
			String typeName = type.getAttribute("name");
			String typeFileName = type.getAttribute("file");
			loadModelType(typeName, typeFileName);
		}
		String transFileName = root.getAttribute("file");
		loadTransformation(transFileName);
		targetFileName = root.getAttribute("target");
		NodeList models = root.getElementsByTagName("model");
		length = models.getLength();
		for(int i=0;i<length;i++){
			Node n = models.item(i);
			if(n.getNodeType()!=Node.ELEMENT_NODE)
				continue;
			Element model = (Element) n;
			String type = model.getAttribute("type");
			String modelFileName = model.getAttribute("file");
			String target = model.getAttribute("isTarget");
			boolean isTarget = false;
			if(target != null && target.equals("true"))
				isTarget = true;
			loadModel(type, modelFileName, isTarget);
		}
		String exceptionFileName = root.getAttribute("exceptionfile");
		loadExceptionRegistry(exceptionFileName);
	}
	
	public static void main(String[] arg) throws Exception{
		PKUTESLoader loader = new PKUTESLoader();
		loader.load("exceptiontest\\test.xml");
		
		long start = System.currentTimeMillis();
		loader.env.getTransformation().accept(loader.env.getMtVisitor());
		System.out.println("Time: "+ (System.currentTimeMillis() - start));
		loader.saveTargetModel("");
	}
}
